package com.bes.bessdk.scan;

import static android.bluetooth.BluetoothDevice.DEVICE_TYPE_CLASSIC;
import static android.bluetooth.BluetoothDevice.DEVICE_TYPE_LE;
import static android.bluetooth.le.ScanSettings.SCAN_MODE_LOW_LATENCY;
import static android.content.ContentValues.TAG;

import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.provider.Settings;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.bes.sdk.device.HmDevice;
import com.bes.sdk.scan.BleBroadCastParser;
import com.bes.sdk.scan.ScanFilter;
import com.bes.sdk.scan.ScanManager;
import com.bes.sdk.utils.DeviceProtocol;

import java.util.Collection;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

public class BesScanManager implements ScanManager {

    private Context mContext;

    private BluetoothAdapter mBluetoothAdapter;
    private BluetoothAdapter bluetoothAdapter;
    private BluetoothLeScanner mLeScanner;

    private ScanListener mCallBack;

    private Timer timer;
    private TimerTask task;
    private int searchDevices = 0;
    private DeviceProtocol curDeviceProtocol;
    @SuppressLint("MissingPermission")
    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            switch (intent.getAction()) {
                case BluetoothAdapter.ACTION_DISCOVERY_STARTED:
                    // Log.d(TAG, "onScanResult ACTION_DISCOVERY_STARTED: --------" );
                    break;
                case BluetoothAdapter.ACTION_DISCOVERY_FINISHED:
                    // Log.d(TAG, "onScanResult ACTION_DISCOVERY_FINISHED: --------" );
                    break;
                case BluetoothDevice.ACTION_FOUND:
                    BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                    if (null == device || device.getName() == null) {
                        return;
                    }
                    Log.i(TAG, "onScanResult spp: device = " + device + ",device name = " + device.getName());
                    HmDevice hmDevice = new HmDevice();
                    hmDevice.setDeviceName(device.getName());
                    if (curDeviceProtocol == DeviceProtocol.PROTOCOL_BLE && (device.getType() & DEVICE_TYPE_LE) != 0) {
                        hmDevice.setPreferredProtocol(DeviceProtocol.PROTOCOL_BLE);
                        hmDevice.setBleAddress(device.getAddress());
                    } else if (curDeviceProtocol == DeviceProtocol.PROTOCOL_SPP && (device.getType() & DEVICE_TYPE_CLASSIC) != 0) {
                        hmDevice.setPreferredProtocol(DeviceProtocol.PROTOCOL_SPP);
                        hmDevice.setDeviceMAC(device.getAddress());
                    } else {
                        return;
                    }
                    int rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI, (short) -100);
                    hmDevice.setRssi(rssi);
                    if (mCallBack != null) {
                        mCallBack.onScanResult(hmDevice);
                    }
                    break;
            }
        }
    };
    @SuppressLint("MissingPermission")
    private android.bluetooth.le.ScanCallback mLeScanCallBack = new android.bluetooth.le.ScanCallback() {

        @Override
        public void onScanFailed(int errorCode) {
            super.onScanFailed(errorCode);
            Log.i(TAG, "onScanFailed: -----" + errorCode);
            if (mCallBack != null) {
                mCallBack.onScanFailed("" + errorCode);
            }
        }

        @Override
        public void onScanResult(int callbackType, ScanResult result) {
            HmDevice hmDevice;
            if (result.getDevice().getName() == null) {
                return;
            }
            Log.i(TAG, "onScanResult ble: device = " + result.getDevice() + ",device name = " + result.getDevice().getName() + ",rssi = " + result.getRssi());
            searchDevices++;
            hmDevice = new HmDevice();
            hmDevice.setDeviceName(result.getDevice().getName());
            hmDevice.setPreferredProtocol(DeviceProtocol.PROTOCOL_BLE);
            hmDevice.setBleAddress(result.getDevice().getAddress());
            hmDevice.setRssi(result.getRssi());
            if (mCallBack != null) {
                mCallBack.onScanResult(hmDevice);
            }
        }
    };

    public BesScanManager(Context context) {
        mContext = context;
        mBluetoothAdapter = BtHeleper.getBluetoothAdapter(mContext);
        initReceiver();
    }

    private void initReceiver() {
        IntentFilter filter = new IntentFilter();
        filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
        filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
        filter.addAction(BluetoothDevice.ACTION_FOUND);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            mContext.registerReceiver(mReceiver, filter, Context.RECEIVER_EXPORTED);
        } else {
            mContext.registerReceiver(mReceiver, filter);
        }
    }

    @SuppressLint("MissingPermission")
    private void getConnectBtDetails(int flag) {
        bluetoothAdapter.getProfileProxy(mContext, new BluetoothProfile.ServiceListener() {
            @Override
            public void onServiceDisconnected(int profile) {

            }

            @Override
            public void onServiceConnected(int profile, BluetoothProfile proxy) {
                List<BluetoothDevice> mDevices = proxy.getConnectedDevices();
                if (mDevices != null && !mDevices.isEmpty() && curDeviceProtocol == DeviceProtocol.PROTOCOL_SPP) {
                    for (BluetoothDevice device : mDevices) {
                        HmDevice hmDevice = new HmDevice();
                        hmDevice.setDeviceName(device.getName());
                        hmDevice.setPreferredProtocol(DeviceProtocol.PROTOCOL_SPP);
                        hmDevice.setDeviceMAC(device.getAddress());
                        if (mCallBack != null) {
                            mCallBack.onScanResult(hmDevice);
                        }
                    }
                }
            }
        }, flag);
    }

    @SuppressLint("MissingPermission")
    private int getConnectBt() {
        if (bluetoothAdapter == null) {
            bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        }
        int a2dp = bluetoothAdapter.getProfileConnectionState(BluetoothProfile.A2DP);
        int headset = bluetoothAdapter.getProfileConnectionState(BluetoothProfile.HEADSET);
        int health = bluetoothAdapter.getProfileConnectionState(BluetoothProfile.HEALTH);
        int flag = -1;
        if (a2dp == BluetoothProfile.STATE_CONNECTED) {
            flag = a2dp;
        } else if (headset == BluetoothProfile.STATE_CONNECTED) {
            flag = headset;
        } else if (health == BluetoothProfile.STATE_CONNECTED) {
            flag = health;
        }
        return flag;
    }

    @Override
    public boolean isScanInProgress(@NonNull DeviceProtocol deviceProtocol) {
        return false;
    }

    @SuppressLint("MissingPermission")
    @Override
    public void startScan(@NonNull Collection<DeviceProtocol> deviceProtocols, @NonNull ScanListener scanListener, @Nullable ScanFilter scanFilter) {
        Log.i(TAG, "startScan: ---------------------123123");
        if (scanListener == null) {
            return;
        }
        mCallBack = scanListener;
        if (mLeScanner != null) {
//            mLeScanner.stopScan(mLeScanCallBack);
            mLeScanner = null;
        }
        // Log.d(TAG," begin check permission.");
        if (new BtPermission(mContext).checkConditions() && mCallBack != null) {
            if (deviceProtocols.contains(DeviceProtocol.PROTOCOL_BLE)) {
                curDeviceProtocol = DeviceProtocol.PROTOCOL_BLE;
                getConnectBtDetails(getConnectBt());
                mBluetoothAdapter.startDiscovery();
                new Thread(() -> {
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    // Log.d(TAG," begin to scan ble.");
                    if (mBluetoothAdapter != null) {
//                        startTimer();
                        mLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
                        if (mLeScanner != null) {
                            ScanSettings scanSettings = new ScanSettings.Builder().setScanMode(SCAN_MODE_LOW_LATENCY) // SCAN_MODE_BALANCED
                                    // SCAN_MODE_LOW_LATENCY
                                    // SCAN_MODE_LOW_POWER
                                    .setLegacy(false).setPhy(ScanSettings.PHY_LE_ALL_SUPPORTED).setNumOfMatches(ScanSettings.MATCH_NUM_MAX_ADVERTISEMENT).setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES).setMatchMode(ScanSettings.MATCH_MODE_AGGRESSIVE).build();
                            // Log.d(TAG," bes scan manager begin scan");
                            mLeScanner.startScan(null, scanSettings, mLeScanCallBack);
                        } else {
                            Intent intent = new Intent(Settings.ACTION_BLUETOOTH_SETTINGS);
                            mContext.startActivity(intent);
                        }
                    } else {
                        // Log.d(TAG," begin to scan ble fail,return.");
                    }
                }).start();

            } else if (deviceProtocols.contains(DeviceProtocol.PROTOCOL_SPP)) {
                curDeviceProtocol = DeviceProtocol.PROTOCOL_SPP;
                getConnectBtDetails(getConnectBt());
                mBluetoothAdapter.startDiscovery();
            }
        }
    }

    @SuppressLint("MissingPermission")
    private void startTimer() {
        searchDevices = 0;

        if (timer != null) {
            timer.cancel();
            timer = null;
        }
        timer = new Timer();
        task = new TimerTask() {
            @Override
            public void run() {
                if (searchDevices < 3) {
                    mLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
                    if (mLeScanner != null) {
                        mLeScanner.startScan(null, new ScanSettings.Builder().setScanMode(SCAN_MODE_LOW_LATENCY).build(), mLeScanCallBack);
                    }
                } else {
                    timer.cancel();
                    timer = null;
                }
            }
        };

        timer.schedule(task, 3 * 1000, 2 * 1000);
    }

    @Override
    public void startScan(@NonNull Collection<DeviceProtocol> deviceProtocols, @NonNull ScanListener scanListener, @Nullable ScanFilter scanFilter, @Nullable BleBroadCastParser parser) {
        if (deviceProtocols.contains(DeviceProtocol.PROTOCOL_BLE)) {

        } else if (deviceProtocols.contains(DeviceProtocol.PROTOCOL_SPP)) {

        }
    }

    @SuppressLint("MissingPermission")
    @Override
    public void stopScan(@NonNull Collection<DeviceProtocol> deviceProtocols) {
        if (deviceProtocols == null){
            return;
        }
        if (deviceProtocols.contains(DeviceProtocol.PROTOCOL_BLE) && mLeScanner != null) {
            mLeScanner.stopScan(mLeScanCallBack);
            Log.d(TAG, " BES stop scan");
            mLeScanner = null;
            // mLeScanCallBack = null;
        }
        if (mBluetoothAdapter != null) {
            mBluetoothAdapter.cancelDiscovery();
        }
        mBluetoothAdapter = null;
        mContext = null;
        if (timer != null) {
            timer.cancel();
            timer = null;
        }
    }

    @Override
    public void stopAllScan() {

    }

    @Override
    public Collection<HmDevice> getDeviceList() {
        return null;
    }

}
